{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Task Solving with Code Generation, Execution and Debugging\n",
    "\n",
    "In this notebook, we demonstrate how to use `AssistantAgent` and `UserProxyAgent` to write code and execute the code. Here `AssistantAgent` is an LLM-based agent that can write Python code (in a Python coding block) for a user to execute for a given task. `UserProxyAgent` is an agent which serves as a proxy for the human user to execute the code written by `AssistantAgent`, or automatically execute the code. Depending on the setting of `human_input_mode` and `max_consecutive_auto_reply`, the `UserProxyAgent` either solicits feedback from the human user or returns auto-feedback based on the result of code execution (success or failure and corresponding outputs) to `AssistantAgent`. `AssistantAgent` will debug the code and suggest new code if the result contains error. The two agents keep communicating to each other until the task is done.\n",
    "\n",
    "````{=mdx}\n",
    ":::info Requirements\n",
    "Install the following packages before running the code below:\n",
    "```bash\n",
    "pip install ag2[openai] matplotlib yfinance\n",
    "```\n",
    "\n",
    "For more information, please refer to the [installation guide](https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/installing-ag2).\n",
    ":::\n",
    "````"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "import autogen\n",
    "from autogen.coding import LocalCommandLineCodeExecutor\n",
    "\n",
    "filter_dict = {\"tags\": \"gpt-4\"}\n",
    "llm_config = autogen.LLMConfig.from_json(path=\"OAI_CONFIG_LIST\", cache_seed=41, temperature=0).where(**filter_dict)\n",
    "\n",
    "# When using a single openai endpoint, you can use the following:\n",
    "# llm_config = autogen.LLMConfig(config_list={\"api_type\": \"openai\", \"model\": \"gpt-4\", \"api_key\": os.environ.get(\"OPENAI_API_KEY\"), \"cache_seed\": 41, \"temperature\": 0})"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example Task: Check Stock Price Change\n",
    "\n",
    "In the example below, let's see how to use the agents in AutoGen to write a python script and execute the script. This process involves constructing a `AssistantAgent` to serve as the assistant, along with a `UserProxyAgent` that acts as a proxy for the human user. In this example demonstrated below, when constructing the `UserProxyAgent`,  we select the `human_input_mode` to \"NEVER\". This means that the `UserProxyAgent` will not solicit feedback from the human user. It stops replying when the limit defined by `max_consecutive_auto_reply` is reached, or when `is_termination_msg()` returns true for the received message."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create an AssistantAgent named \"assistant\"\n",
    "assistant = autogen.AssistantAgent(name=\"assistant\", llm_config=llm_config)\n",
    "\n",
    "# create a UserProxyAgent instance named \"user_proxy\"\n",
    "user_proxy = autogen.UserProxyAgent(\n",
    "    name=\"user_proxy\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    max_consecutive_auto_reply=10,\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\"),\n",
    "    code_execution_config={\n",
    "        # the executor to run the generated code\n",
    "        \"executor\": LocalCommandLineCodeExecutor(work_dir=\"coding\"),\n",
    "    },\n",
    ")\n",
    "# the assistant receives a message from the user_proxy, which contains the task description\n",
    "chat_res = user_proxy.initiate_chat(\n",
    "    assistant,\n",
    "    message=\"\"\"What date is today? Compare the year-to-date gain for META and TESLA.\"\"\",\n",
    "    summary_method=\"reflection_with_llm\",\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The example above involves code execution. In AutoGen, code execution is triggered automatically by the `UserProxyAgent` when it detects an executable code block in a received message and no human user input is provided. \n",
    "Users have the option to specify a different working directory by setting the `work_dir` argument when constructing a new instance of the `LocalCommandLineCodeExecutor`.\n",
    "For Docker-based or Jupyter kernel-based code execution, please refer to \n",
    "[Code Executors Tutorial](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/code-execution) for more information."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Check chat results\n",
    "The `initiate_chat` method returns a `ChatResult` object, which is a dataclass object storing information about the chat. Currently, it includes the following attributes:\n",
    "\n",
    "- `chat_history`: a list of chat history.\n",
    "- `summary`: a string of chat summary. A summary is only available if a summary_method is provided when initiating the chat.\n",
    "- `cost`: a tuple of (total_cost, total_actual_cost), where total_cost is a dictionary of cost information, and total_actual_cost is a dictionary of information on the actual incurred cost with cache.\n",
    "- `human_input`: a list of strings of human inputs solicited during the chat. (Note that since we are setting `human_input_mode` to `NEVER` in this notebook, this list is always empty.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Chat history:\", chat_res.chat_history)\n",
    "\n",
    "print(\"Summary:\", chat_res.summary)\n",
    "print(\"Cost info:\", chat_res.cost)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example Task: Plot Chart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# followup of the previous question\n",
    "user_proxy.send(\n",
    "    recipient=assistant,\n",
    "    message=\"\"\"Plot a chart of their stock price change YTD. Save the data to stock_price_ytd.csv, and save the plot to stock_price_ytd.png.\"\"\",\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's display the generated figure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    image = Image(filename=\"coding/stock_price_ytd.png\")\n",
    "    display(image)\n",
    "except FileNotFoundError:\n",
    "    print(\"Image not found. Please check the file name and modify if necessary.\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's display the raw data collected and saved from previous chat as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Path to your CSV file\n",
    "file_path = \"coding/stock_price_ytd.csv\"\n",
    "try:\n",
    "    with open(file_path, encoding=\"utf-8\") as file:\n",
    "        # Read each line in the file\n",
    "        for line in file:\n",
    "            # Split the line into a list using the comma as a separator\n",
    "            row = line.strip().split(\",\")\n",
    "            # Print the list representing the current row\n",
    "            print(row)\n",
    "except FileNotFoundError:\n",
    "    print(\"File not found. Please check the file name and modify if necessary.\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example Task: Use User Defined Message Function to let Agents Analyze data Collected\n",
    "\n",
    "Let's create a user defined message to let the agents analyze the raw data and write a blogpost. The function is supposed to take `sender`, `recipient` and `context` as inputs and outputs a string of message.\n",
    "\n",
    "**kwargs from `initiate_chat` will be used as `context`. Take the following code as an example, the `context` includes a field `file_name` as provided in `initiate_chat`. In the user defined message function `my_message_generator`, we are reading data from the file specified by this filename.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_message_generator(sender, recipient, context):\n",
    "    # your CSV file\n",
    "    file_name = context.get(\"file_name\")\n",
    "    try:\n",
    "        with open(file_name, encoding=\"utf-8\") as file:\n",
    "            file_content = file.read()\n",
    "    except FileNotFoundError:\n",
    "        file_content = \"No data found.\"\n",
    "    return \"Analyze the data and write a brief but engaging blog post. \\n Data: \\n\" + file_content\n",
    "\n",
    "\n",
    "# followup of the previous question\n",
    "chat_res = user_proxy.initiate_chat(\n",
    "    recipient=assistant,\n",
    "    message=my_message_generator,\n",
    "    file_name=\"coding/stock_price_ytd.csv\",\n",
    "    summary_method=\"reflection_with_llm\",\n",
    "    summary_args={\"summary_prompt\": \"Return the blog post in Markdown format.\"},\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check the summary of the chat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(chat_res.summary)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is the blog post that the agents generated.\n",
    "\n",
    "# A Comparative Analysis of META and TESLA Stocks in Early 2024\n",
    "\n",
    "In the first quarter of 2024, the stock market saw some interesting movements in the tech sector. Two companies that stood out during this period were META and TESLA. \n",
    "\n",
    "META, the social media giant, had an average stock price of 403.53 during this period. The highest it reached was 519.83, while the lowest was 344.47. The standard deviation, a measure of how spread out the prices were, was 100.72.\n",
    "\n",
    "On the other hand, TESLA, the electric vehicle and clean energy company, had an average stock price of 219.54. The stock reached a high of 248.42 and a low of 171.76. The standard deviation for TESLA was 41.68.\n",
    "\n",
    "These figures show that both META and TESLA had their ups and downs during this period. However, the higher standard deviation for META indicates that its stock price fluctuated more compared to TESLA.\n",
    "\n",
    "As we move further into 2024, it will be interesting to see how these trends evolve. Will META and TESLA continue on their current trajectories, or will we see a shift in the market dynamics? Only time will tell."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check how much the above chat cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(chat_res.cost)"
   ]
  }
 ],
 "metadata": {
  "front_matter": {
   "description": "Use conversable language learning model agents to solve tasks and provide automatic feedback through a comprehensive example of writing, executing, and debugging Python code to compare stock price changes.",
   "tags": [
    "code generation"
   ]
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  },
  "vscode": {
   "interpreter": {
    "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
